package afcepf.atod18.frameworkMVC2.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class XMLParser {
    private static final Logger logger = Logger.getLogger(XMLParser.class);
    
    final static String NODE_ROOT = "racine";
    final static String NODE_ACTIONS = "actions";
    final static String NODE_ACTION = "action";
    final static String NODE_ACTION_NAME = "action-name";
    final static String NODE_ACTION_URL = "url-pattern";
    final static String NODE_FORM_NAME = "form-name";
    final static String NODE_FORMS = "forms";
    final static String NODE_FORM = "form";
    final static String NODE_FORM_CLASS = "form-class";

    public XMLParser() {
        // TODO Auto-generated constructor stub
    }
    
    private void checkNode( String reference, Element elem ) throws MVC2Exception {
        if (!reference.contentEquals(elem.getNodeName()))
            throw new MVC2Exception(String.format("XMLParser:LoadXML: Node %s expected, got %s ",  reference, elem.getNodeName())); 
    }

    @SuppressWarnings("unused")
    private void checkNode( String reference, Node elem ) throws MVC2Exception {
        if (!reference.contentEquals(elem.getNodeName()))
            throw new MVC2Exception(String.format("XMLParser:LoadXML: Node %s expected, got %s ",  reference, elem.getNodeName())); 
    }

    private void parseActions(Element root) throws MVC2Exception {
        NodeList bases = root.getElementsByTagName(NODE_ACTIONS);
        logger.info(String.format( "XMLParser:LoadXML:Root <%s> child <%s> childcount=%d",NODE_ROOT,NODE_ACTIONS, bases.getLength()));
        if (bases.getLength()==0)
            throw new MVC2Exception("XMLParser:LoadXML:cannot find any "+NODE_ACTIONS);
        
        // parcours des elements ACTIONS
        for (int index=0; index<bases.getLength(); index++) {
            Node node = bases.item(index);
            logger.info( String.format("XMLParser:LoadXML: nodeName <%s>",node.getNodeName()) );
            NodeList actions = node.getChildNodes();
            
            for (int actionIndex = 0; actionIndex < actions.getLength(); actionIndex++) {
                Node action = actions.item(actionIndex);
                logger.info(String.format("XMLParser:LoadXML:   1 child of actions: <%s>", action.getNodeName()));
                //checkNode( NODE_ACTION, action );
                if ( action.getNodeName().contentEquals(NODE_ACTION)) {
                    NodeList childs = action.getChildNodes();
                    
                    String actionName = "";
                    String actionUrl = "";
                    String actionform = "";
                    
                    // parcours des enfants du tag <ACTION>
                    for (int childIndex = 0; childIndex < childs.getLength(); childIndex++) {
                        Node childAction = childs.item(childIndex);
                        logger.info(String.format("XMLParser:LoadXML:      2 child of action <%s>",childAction.getNodeName()));
                        // ACTION-NAME
                        if (childAction.getNodeName().contains(NODE_ACTION_NAME)) {
                            logger.info("XMLParser:LoadXML:                  find  [NODE_ACTION_NAME] "+childAction.getTextContent());
                            actionName = childAction.getTextContent();
                        }
                        // URL-PATTERN
                        if (childAction.getNodeName().contains(NODE_ACTION_URL)) {
                            logger.info("XMLParser:LoadXML:                  find  [NODE_ACTION_URL] "+childAction.getTextContent());
                            actionUrl = childAction.getTextContent();
                        }
                        // FORM-NAME
                        if (childAction.getNodeName().contains(NODE_FORM_NAME)) {
                            logger.info("XMLParser:LoadXML:                   ind  [NODE_FORM_NAME] "+childAction.getTextContent());
                            actionform = childAction.getTextContent();
                        }
                    }
                    // we collect all necessary elements to register action
                    if ( !actionform.isEmpty() && !actionName.isEmpty() && !actionUrl.isEmpty() ) {
                        Builder.getInstance().RegisterAction(actionName, actionUrl, actionform);
                    }
                }
            }
        }
    }
    
    private void parseForms(Element root) throws MVC2Exception {
        NodeList bases = root.getElementsByTagName(NODE_FORMS);
        logger.info(String.format( "XMLParser:LoadXML:Root <%s> child <%s> childcount=%d",NODE_ROOT,NODE_FORMS, bases.getLength()));
        if (bases.getLength()==0)
            throw new MVC2Exception("XMLParser:LoadXML:cannot find any "+NODE_FORMS);
        
        // parcours des elements ACTIONS
        for (int index=0; index<bases.getLength(); index++) {
            Node node = bases.item(index);
            logger.info( String.format("XMLParser:LoadXML: nodeName <%s>",node.getNodeName()) );
            NodeList actions = node.getChildNodes();
            
            for (int actionIndex = 0; actionIndex < actions.getLength(); actionIndex++) {
                Node action = actions.item(actionIndex);
                logger.info(String.format("XMLParser:LoadXML:   1 child of actions: <%s>", action.getNodeName()));
                //checkNode( NODE_ACTION, action );
                if ( action.getNodeName().contentEquals(NODE_FORM)) {
                    NodeList childs = action.getChildNodes();
                    
                    String actionUrl = "";
                    String actionform = "";
                    
                    // parcours des enfants du tag <ACTION>
                    for (int childIndex = 0; childIndex < childs.getLength(); childIndex++) {
                        Node childAction = childs.item(childIndex);
                        logger.info(String.format("XMLParser:LoadXML:      2 child of action <%s>",childAction.getNodeName()));
                        // URL-PATTERN
                        if (childAction.getNodeName().contains(NODE_FORM_CLASS)) {
                            logger.info("XMLParser:LoadXML:                  find  [NODE_FORM_CLASS] "+childAction.getTextContent());
                            actionUrl = childAction.getTextContent();
                        }
                        // FORM-NAME
                        if (childAction.getNodeName().contains(NODE_FORM_NAME)) {
                            logger.info("XMLParser:LoadXML:                   ind  [NODE_FORM_NAME] "+childAction.getTextContent());
                            actionform = childAction.getTextContent();
                        }
                    }
                    // we collect all necessary elements to register action
                    if ( !actionform.isEmpty() && !actionUrl.isEmpty() ) {
                        Builder.getInstance().RegisterForm(actionform, actionUrl);
                    }
                }
            }
        }
    }
    
    public void loadXML(InputStream is) throws ParserConfigurationException, SAXException, IOException, MVC2Exception {
        
        logger.info("-------------------- XMLParser:LoadXML: begin --------------------");
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(is);
        Element root = doc.getDocumentElement();
        logger.info("XMLParser:LoadXML:Rootname "+root.getNodeName());
        checkNode(NODE_ROOT, root);
        parseActions(root);
        parseForms(root);
        logger.info("-------------------- XMLParser:LoadXML: end --------------------");
    }
    
    public void initialize() throws MVC2Exception {
        final String XMLFILENAME = "mvc2.xml";
        
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        URLConnection con = null;
        URL xmlfile = loader.getResource(XMLFILENAME);
        logger.info("XMLParser:initialize:xml resource file "+xmlfile);
        try {
            con = xmlfile.openConnection();
            logger.info("XMLParser:initialize:xml resource connection opened");
        } catch (NullPointerException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new MVC2Exception("XMLParser:initialize:Cannot open a connection to resource file " + XMLFILENAME);
        }
        XMLParser toto = new XMLParser();
        try {
            toto.loadXML( con.getInputStream() );
        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
            throw new MVC2Exception("XMLParser:initialize:Cannot parse resource file " + XMLFILENAME);
        }
    }
}
